
/** @class BlockToggle 
	@description gere un systeme de bloc ouvert/ferme
	@use 
		@return behavior 
*/
var BlockScrollable = new Class({
	required: ["css", "img"],
		
	initialize: function (block, options){
		block = this.block = $(block);
		this.inst = new ScrollBar(block, options)
		var fn = function (){this.inst.rebuild();alert('rouge')}.bind(this);
		Notifier.addEvent("onLayoutChanged", fn	);
	}
		
});
Moodule.register("BlockScrollable", "div.blockScrollable", {
	parent: "page"
});


/**
* 
* The script drives the behaviour and the positionning, the skin is manage by CSS
*
* @use 
    new scrollBar('id', {speed:30, scrollMargin:[10, 5, 10]}, {})
    new scrollBar(document.getElementByTagName('p')[3], {}, {})
* @class scrollBar
* @param elm {string|htmlElement}id|elm
* @param conf {object}
*   @param speed {float|percentage}
*   @param parent {string|htmlElement} in wich element the scrollBar will be inject. default:document.body
*       use with the layer element if the scrollBar need to be inject in a layer, 
*       if not, leave it by default 
*   @param scrollMargin {int|array} fonctionne comme css si 
        1 arg > 4 margin,
        si 2 args > vert hor,
        si 3 top vert bottom,
        si 4 args > top right bottom left
    @param step {integer} not implemented
* @param callbacks {object}
*   @param onDragStart {function} will be executed with the object(this) as parameters
*   @param onDrag {function} will be executed with the object(this) as parameters
*   @param onDragEnd {function} will be executed with the object(this) as parameters
 **/

	

var ScrollBar = new Class({
	Implements: Options,
		
	options: {
		// onDrag: $empty(),
		// onTop: $empty(),
		// onBottom: $empty(),
		// onLeft: $empty(),
		// onRight: $empty(),
		speed: 1,
		parent: document.body,
		margin: [4, -4],
		step: false,
		wheelRatio: 1,
		arrowRatio: 2,
		roadRatio: 5,
		arrowKeyRatio: 5,
		pageKeyRatio: 10,
		spaceKeyRatio: 10,
		mode: "simple"
		
	},
    initialize: function (elm, options){
		this.setOptions(options);
		this.margins = this.setMargins();
        elm = this.elm = $(elm);
		// scripts vars
        this.elm.scrollTop = 0;
		this.pourcent = 0;
		
        
        // build the scroller
        this.build();
        
        // this.update();
        // behavior
        // this.mode == "vertical" ? this._addEventsV() : this._addEventsH();
        
        
    },
    
	rebuild: function (){
		if(this.container) this.container.dispose();
		this.build();
	},
	
    build: function (){
        // creation de la structure 1 <div> + 4 <a>
        if($("scroller_"+ this.elm.id)) return;
		this.container = new Element('div', {
			"id": this.elm.id != "" ? "scroller_"+ this.elm.id : "scroller_"+((new Date()).getTime()),
			"class": "verticalScrollBar"
		});
        
		// inject into DOM
        $(document.body).adopt(this.container);
        
		// give space in the bottom if vertical
		//this.elm.innerHTML += "<hr style='visibility:hidden;'/>";
        
		// structure
		var classes = ["scrollerNW","scrollerRoad","scrollerSE","scrollerLift"];
        
        for(var i=0,l=classes.length;i<l;i++){
            var str = classes[i];
            this[str] = new Element('span', {"class": str, "tabindex": "-1"});
            this.container.adopt(this[str]);
        }
        
        // ajout des elements extensibles 3 span + resizebody
        this.scrollerRoad.innerHTML = "<span class='tp'></span><span class='bd'></span><span class='ft'></span>";
        this.scrollerLift.innerHTML = "<span class='tp'></span><span class='bd'></span><span class='ft'></span>";
        
        if(this.mode == "both") throw("scrollBar vertical AND horizontal is not implemented yet.")
        
        // keep close the elements
        this.spans = this.container.getElements('span');
        this.as = this.container.getElements('a');
		
		// positionate the scroller
		this.positionate();
        this._addEvents();
		this.options.mode == "complex" ? this._addComplexEvents() : this._addSimpleEvents();
    },
    
	setMargins: function (){
        var margin = this.options.margin;
        // if 1 arg
        if(typeof margin == "string" || typeof margin == "number") return [margin,margin,margin,margin];
        
        // 2,3,4 args
        switch(margin.length){
            case 2:
                return [margin[0],margin[1],margin[0],margin[1]]
                break;
            case 3:
                return [margin[0],margin[1],margin[2],margin[1]]
                break;
            case 4:
                return [margin[0],margin[1],margin[2],margin[3]]
                break;
        }
    },
	
	positionate: function (){
		// check if a scrollBar is necessary
        if(this.elm.scrollHeight <= this.elm.offsetHeight && this.elm.scrollWidth <= this.elm.offsetWidth){
			this.container.setStyles({
				"display": "none"
			});
		}
		else {
			this.elm.scrollTop = 0;
			this._clear();
			var coo = this.elm.getCoordinates();
			this.container.setStyles({
				"top": coo.top + this.margins[0],
				"left": coo.right + this.margins[3],
				"display": "block"
			});
			
			this.scrollerRoad.getElement(".bd").setStyle('height', coo.height - this.container.offsetHeight - this.margins[0] - this.margins[2] );
			this.scrollerLift.setStyles({
				'top' : this.scrollerNW.offsetHeight
			});
			
			this.ratio = this.elm.scrollHeight / this.elm.offsetHeight;
			this.scrollerLift.getElement(".bd").style.height = (this.scrollerRoad.offsetHeight / this.ratio) - this.scrollerLift.getElement(".tp").offsetHeight - this.scrollerLift.getElement(".ft").offsetHeight + 'px';
			
			this.elmDebate = (this.elm.scrollHeight - this.elm.offsetHeight) / 100;
			this.liftDebate = (this.scrollerRoad.offsetHeight - this.scrollerLift.offsetHeight) /  100;
		
		}
	},
	
	_clear: function (){
		this.scrollerRoad.getElement(".bd").setStyle('height', "");
		this.scrollerLift.getElement(".bd").setStyle('height', "");
	},
	
    _addEvents : function (){ // generic events
        /*scrollerTop*/
        this.scrollerNW.addEvents({
			"mousedown": function (e){
				this._startScroll(-this.options.arrowRatio, {min:0})
			}.bind(this),
			"mouseup": function (){
				this._stopScroll()
			}.bind(this)
		})
		
		
        /*scrollerBottom */
        this.scrollerSE.addEvents({
			"mousedown": function (e){
				this._startScroll(this.options.arrowRatio, {max:100000})
			}.bind(this),
			"mouseup": function (){
				this._stopScroll()
			}.bind(this)
		})
		
        /*scrollerRoad*/
        this.scrollerRoad.addEvents({
			"mousedown": function (e){
				var coo = this.scrollerLift.getCoordinates();
				var direction = e.page.y > coo.top ? 1 : -1;
				this._startScroll(direction * this.options.roadRatio, {})
			}.bind(this),
			"mouseup": function (){
				this._stopScroll()
			}.bind(this),
			"mouseleave": function (){
				this._stopScroll()
			}.bind(this)
		})
        
		var Ymin = this.scrollerNW.offsetHeight;
		var Ymax = this.scrollerRoad.offsetHeight + this.scrollerNW.offsetHeight - this.scrollerLift.offsetHeight;
        /*scrollerLift*/	
		var xx = new Drag(this.scrollerLift, {
			limit: {x:0, y:[Ymin, Ymax]},
			modifiers: {x:"", y:"top"},
			onDrag: function (elm, oData){
				var delta = ((elm.getCSS("top", true) - this.scrollerNW.offsetHeight) / this.liftDebate) - this.pourcent;
				this._moveScroll(delta, true);
			}.bind(this),
			onStart : function (elm, oData){
				elm.addClass("grabbin");
			},
			onComplete : function (elm, oData){
				elm.removeClass("grabbin");
			}
		})
		
		// event functions
		var keyEvent = function (e){
			switch(e.event.keyCode){
				case 40:
					e.stop();
					this._moveScroll(this.options.arrowKeyRatio, false);
					break;
				case 38:
					e.stop();
					this._moveScroll(-this.options.arrowKeyRatio, false);
					break;
				case 34:
					e.stop();
					this._moveScroll(this.options.pageKeyRatio, false);
					break;
				case 33:
					e.stop();
					this._moveScroll(-this.options.pageKeyRatio, false);
					break;
				case 32:
					e.stop();
					this._moveScroll(100/this.ratio, false);
					break;
			}
		}.bind(this)
		
		var stop = function (){
			this._stopScroll();
		}.bind(this)
		
		
		this.elm.addEvents({
			"mousewheel": function (e){
				e.stop();
				var delta = -e.wheel * this.options.wheelRatio;
				this._moveScroll(delta, false);
			}.bind(this),
			
			"mouseenter": function (e){
				addEvent("keydown", keyEvent)
				addEvent("keyup", stop)
			}.bind(this),
			"mouseleave": function (e){
				removeEvent("keydown", keyEvent)
				removeEvent("keyup", stop)
			}.bind(this)
			
		});
		
		this.container.addEvents({
			"mousewheel": function (e){
				e.stop();
				var delta = -e.wheel * this.options.wheelRatio;
				this._moveScroll(delta, false);
			}.bind(this),
			
			"mouseenter": function (e){
				addEvent("keydown", keyEvent)
				addEvent("keyup", stop)
			}.bind(this),
			"mouseleave": function (e){
				removeEvent("keydown", keyEvent)
				removeEvent("keyup", stop)
			}.bind(this)
			
		});
	},
	
    _addSimpleEvents: function (){},
    
	_addComplexEvents: function (){},
    
	hide : function(){
        this.container.style.display = "none";
        this.isHide = true;
    },
    
    show : function(){
        this.container.style.display = "";
        this.isHide = false;
    },
    
    toggle : function(){
        this.isHide == true ? this.show() : this.hide();
    },
    
	_startScroll: function (delta, opts){
		opts = opts || {};
		this._stopScroll();
		this.interval = setInterval(function (){
			this._moveScroll(delta, false);
			if(opts.max && this.pourcent >= opts.max){
				this._stopScroll();
				this._moveScroll(opts.max, false);
			}
			else if(opts.min && this.pourcent <= opts.min){
				this._stopScroll();
				this._moveScroll(opts.min, false);
			}
		}.bind(this), 50)
	},
	
    _moveScroll : function (delta, fromDrag){
		this.pourcent += delta;
		if (this.pourcent>100) this.pourcent = 100;
		if (this.pourcent<0) this.pourcent = 0;
		this.elm.scrollTop = this.elmDebate * this.pourcent;
		if(!fromDrag) this.scrollerLift.setStyle('top',  (this.liftDebate * this.pourcent) + this.scrollerNW.offsetHeight );
    },
    
    _stopScroll : function (){
		if(this.interval) clearInterval(this.interval);
    },
	
    destroy : function (instance){
		if(!this.container) return;
		if(this.container.parentNode) this.container.parentNode.removeChild(this.container);
		if(instance){
			if(instance.interval) clearInterval(instance.interval);
			delete instance;
		}
        instance = null;
		Object.reset(this);
		TBL.Functions.destroyScrollBar(this);
    }
})

TBL.Functions.destroyScrollBar = function (inst){
	Object.reset(inst);
}